<?php
declare(strict_types=1);

namespace App\AiPro\Service;

use GuzzleHttp\Client;
use Hyperf\Coroutine\Coroutine;
use Hyperf\Coroutine\Parallel;
use Monolog\Logger;

class BrushClass
{
    protected $token;
    protected $randomCode;
    protected $classDict = [];
    protected $stid;

    public function __construct()
    {
//        assert(strpos($token, 'aHR') === 0, 'Token格式不对,应该是aHR开头!');
        $this->token = 'aHR0cDovL3d3dy41MWl4dWVqaWFvLmNvbS9zdHVkZW50L2NvdXJzZS9pbmRleDphY2NUZkg3RWFoOHhGb2ZSTWFlTGlhYlhIWDFJV0hzYXlnUVpidC9xNjdySXRQRDhzblNpU1B2U01RRDNzWnFNQTdTSEttTUxtcTBzU2lXYllOL29Ca1hoM05ScFdxL0Nkakl4WU1NcHI0YlNQekZ0VWdodGdSK2lRPT0=';
        $this->randomCode = $this->generateWebkitBoundary();
        $this->classDict = [];
        $this->stid = $this->getStid();
    }

    public static function generateWebkitBoundary(int $randomPartLength = 16): string
    {
        $prefix = "WebKitFormBoundary";
        $randomPart = substr(str_shuffle(str_repeat($x='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', (int)ceil($randomPartLength / strlen($x)))),1,$randomPartLength);
        return $prefix . $randomPart;
    }

    public function apiHeaders(): array
    {
        return [
            "Host" => "www.51ixuejiao.com",
            "Connection" => "keep-alive",
            "X-Custom-Return" => "json",
            "Authorization" => "Basic " . $this->token,
            "X-Custom-Action" => "null",
            "X-Custom-Header" => "WeishaKeji",
            "Access-Control-Allow-Methods" => "POST,GET,DELETE,PUT,PATCH,HEAD,OPTIONS",
            "Accept" => "application/json, text/plain, */*",
            "User-Agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.188",
            "Encrypt" => "true",
            "Access-Control-Allow-Headers" => "X-Requested-With",
            "X-Custom-Method" => "get",
            "Referer" => "http://www.51ixuejiao.com/student/course/index",
        ];
    }

    public function olidHeaders(): array
    {
        return [
            "Host" => "www.51ixuejiao.com",
            "Proxy-Connection" => "keep-alive",
            "Accept" => "application/json, text/plain, */*",
            "Access-Control-Allow-Headers" => "X-Requested-With",
            "Authorization" => "Basic " . $this->token,
            "X-Custom-Header" => "weishakeji",
            "Access-Control-Allow-Methods" => "POST,GET,DELETE,PUT,PATCH,HEAD,OPTIONS",
            "User-Agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36",
            "Referer" => "http://www.51ixuejiao.com/web/course/study.712",
        ];
    }

    public function brushOneClass($couid, $olid)
    {
        try {
            $code = $this->randomCode;
            $url = 'http://www.51ixuejiao.com/api/v1/Course/StudyLog';
            $data = "------{$code}\r\n";
            $data .= "Content-Disposition: form-data; name=\"couid\"\r\n\r\n{$couid}\r\n";
            $data .= "------{$code}\r\n";
            $data .= "Content-Disposition: form-data; name=\"olid\"\r\n\r\n{$olid}\r\n";
            $data .= "------{$code}\r\n";
            $data .= "Content-Disposition: form-data; name=\"playTime\"\r\n\r\n3600\r\n";
            $data .= "------{$code}\r\n";
            $data .= "Content-Disposition: form-data; name=\"studyTime\"\r\n\r\n3600\r\n";
            $data .= "------{$code}\r\n";
            $data .= "Content-Disposition: form-data; name=\"totalTime\"\r\n\r\n3600\r\n";
            $data .= "------{$code}--\r\n";

            $client = new Client('www.51ixuejiao.com');
            $client->setHeaders($this->apiHeaders());
            $client->set(['timeout' => 5]);
            $client->post($url, $data);
            $response = $client->body;
            $client->close();

            $data = base64_decode($response);
            $data = json_decode($data, true);
            if (preg_match('/success"\s*:\s*true/', $data)) {
                return true;
            }
        } catch (\Throwable $e) {
            return;
        }
    }

    public function decodeUnicode($encodedUnicode)
    {
        $encodedUnicode = str_replace('%u', '\\u', $encodedUnicode);
        return mb_convert_encoding($encodedUnicode, 'UTF-8', 'ASCII');
    }

    public function getStid()
    {
        $url = 'http://www.51ixuejiao.com/api/v1/Account/Current';
        $client = new Client('www.51ixuejiao.com');
        $client->setHeaders($this->apiHeaders());
        $client->set(['timeout' => 5]);
        $client->get($url);
        $response = $client->body;
        $client->close();

        $data = base64_decode($response);
        preg_match('/Ac_ID*"\s*:\s*(\d+),/', $data, $matches);
        return $matches[1] ?? null;
    }

    public function getAllClass()
    {
        $url = 'http://www.51ixuejiao.com/api/v1/Course/purchased';
        $params = [
            "acid" => $this->stid,
            "search" => "",
            "enable" => "true",
            "size" => "10",
            "index" => "1"
        ];

        $client = new Client('www.51ixuejiao.com');
        $client->setHeaders($this->apiHeaders());
        $client->set(['timeout' => 5]);
        $client->get($url, $params);
        $response = $client->body;
        $client->close();

        $data = base64_decode($response);
        $data = preg_replace('/eval\(.*?rce\)/', '""', $data);
        $data = json_decode($data, true);

        $classesInfo = $data['result'] ?? [];
        foreach ($classesInfo as $info) {
            $couids = $info['Cou_ID'] ?? null;
            $className = $info['Cou_Name'] ?? null;
            $className = $this->decodeUnicode($className);
            $olids = $this->getOlids($couids);
            if (!$olids) {
                return;
            }
            $this->classDict[$couids] = [
                "olids" => $olids,
                "name" => $className
            ];
            echo "识别到账号课程:\n{$className}----Couids:{$couids}----Olids:{$olids}\n";
        }
        return $this->classDict;
    }

    public function getOlids($couids)
    {
        $url = "http://www.51ixuejiao.com/api/v1/Course/LogForOutlineVideo?stid={$this->stid}&couid={$couids}";
        $client = new Client('www.51ixuejiao.com');
        $client->setHeaders($this->apiHeaders());
        $client->set(['timeout' => 5]);
        $client->get($url);
        $response = $client->body;
        $client->close();

        $text = base64_decode($response);
        $text = str_replace(' ', '', $text);
        preg_match_all('/Ol_ID\s*:\s*\"(\d+)\"/', $text, $matches);
        return $matches[1] ?? [];
    }

    public function main()
    {
        $sucOnce = 0;
        $badOnce = 0;
        $this->getAllClass();
        $sumLesson = 0;
        foreach ($this->classDict as $x) {
            $sumLesson += count($x["olids"]);
        }
        echo "数据获取完毕,共计" . count($this->classDict) . "个科目,{$sumLesson}节课!\n";
        echo json_encode($this->classDict) . "\n";
        $threads = [];
        for ($i = 0; $i < 20; ++$i) {
            $parallel = new Parallel(5); // 这里设置最大并发数为 10
            Coroutine::create(function () use ($parallel,&$threads) {
                foreach ($this->classDict as $key => $value) {
                    $couid = $key;
                    $name = $value["name"];
                    foreach ($value["olids"] as $olid) {
                        $result = $this->brushOneClass($couid, $olid);
                        $name = "课程:{$name} | Couid:{$couid} | Olid:{$olid}";
                        if ($result) {
                            $sucOnce++;
                        } else {
                            $badOnce++;
                        }
                        echo "{$name} : " . ($result ? "完成" : "失败!!!!!") . "\n";
                    }
                    $parallel->wait();
                }
            });
        }
        Coroutine::waitFor($threads);
        echo "共计{$sumLesson}节课,成功:{$sucOnce}次,失败:{$badOnce}次!!!\n";
        echo "\n刷课的数据,10分钟后才会更新,不会立即更新!!!!!!\n";
        echo "\n如果想让立即生效，点击->课程->综合成绩->更新学习记录!!!!\n";
    }
}

?>
